package main

import (
	"fmt"
	"github.com/aliyun/aliyun-oss-go-sdk/oss"
	"github.com/spf13/viper"
	"log"
	"os"
	"path"
	"path/filepath"
	"strings"
)

type Config struct {
	Oss struct {
		Key      string `mapstructure:"key"`
		Secret   string `mapstructure:"secret"`
		Endpoint string `mapstructure:"endpoint"`
		Bucket   string `mapstructure:"bucket"`
	}
}

var (
	Cf         = new(Config)
	ConfigPath = "/opt/oss/"
	SourcePath string
	Client     *oss.Client
)

const configTemplate = `
oss:
  key:
  secret:
  endpoint:
  bucket:
`

func FileExist(filePath string) bool {
	status := false
	if _, err := os.Stat(filePath); err == nil || os.IsExist(err) {
		status = true
	} else if !os.IsExist(err) {
		status = false
	}
	return status
}

func ConfigFileWrite() error {
	if !FileExist(ConfigPath) {
		if err := os.MkdirAll(ConfigPath, 0755); err != nil {
			panic(ConfigPath)
		}
	}
	fileObj, err := os.OpenFile(ConfigPath+"config.yml", os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_TRUNC, 0644)
	if err != nil {
		panic(err)
	}
	defer func(fileObj *os.File) {
		err := fileObj.Close()
		if err != nil {

		}
	}(fileObj)
	if _, err := fileObj.WriteString(configTemplate); err != nil {
		panic(err)
	}
	return nil
}

func OssClient(endpoint, key, secret string) (err error) {
	// 创建OSSClient实例。
	Client, err = oss.New(endpoint, key, secret)
	if err != nil {
		panic(err)
	}
	return nil
}

func UploadObj(bucketName, objName, filePath string) (err error) {
	// 获取存储空间。
	bucket, err := Client.Bucket(bucketName)
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	// 上传本地文件。
	err = bucket.PutObjectFromFile(objName, filePath)
	if err != nil {
		panic(err)
	}
	return
}

func IsDir(filePath string) bool {
	s, err := os.Stat(filePath)
	if err != nil {
		panic(err)
	}
	return s.IsDir()
}

func ScanFileToUpload(appName, uploadPath string) error {
	allFiles, _ := filepath.Glob(path.Join(uploadPath, "*"))
	folders := make([]string, 0)
	for _, dir := range allFiles {
		if IsDir(dir) {
			folders = append(folders, filepath.Base(dir))
		}
	}
	if len(folders) > 0 {
		for _, dir := range folders {
			if err := ScanFileToUpload(appName, path.Join(uploadPath, dir)); err != nil {
				return err
			}
		}
	}
	files := make([]string, 0)
	for _, file := range allFiles {
		if !IsDir(file) {
			files = append(files, file)
		}
	}

	for _, localFile := range files {
		ossFilePath := strings.Split(localFile, SourcePath)
		joinOssPath := appName + ossFilePath[len(ossFilePath)-1]
		if err := UploadObj(Cf.Oss.Bucket, joinOssPath, localFile); err != nil {
			return err
		}
	}
	return nil
}

func init() {
	if !FileExist(ConfigPath + "config.yml") {
		if err := ConfigFileWrite(); err != nil {
			panic(err)
		}
		log.Println("请完善配置文件内容，路径：/opt/oss/config.yml")
		os.Exit(1)
	}
	viper.SetConfigFile(ConfigPath + "config.yml")
	if err := viper.ReadInConfig(); err != nil {
		log.Fatalf("read setting file failed, err:%s \n", err)
	}
	if err := viper.Unmarshal(&Cf); err != nil {
		log.Fatalf("unmarshal conf failed, err:%s \n", err)
	}
}

func main() {
	if len(os.Args[1:]) < 2 {
		log.Println("上传失败！error: 需要传入目录名称和文件路径")
		os.Exit(1)
	}
	dirName, localFilePath := os.Args[1], os.Args[2]
	SourcePath = localFilePath
	log.Println("开始连接到oss...")
	if err := OssClient(Cf.Oss.Endpoint, Cf.Oss.Key, Cf.Oss.Secret); err != nil {
		return
	}
	log.Println("扫描目录 开始上传...")
	if err := ScanFileToUpload(dirName, localFilePath); err != nil {
		return
	}
	log.Println("上传成功!")
}
